﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UIElements;
using winS.Unity.Process;
using winS.UnityEditor.GUI;
using winS.UnityEditor.UIElement;
using Label = winS.UnityEditor.UIElement.Label;

namespace winS.UnityEditor.ProcessEditor
{
    /// <summary>
    /// 步骤节点.
    /// 该节点仅提供标题.
    /// 节点的实际视图
    /// </summary>
    public abstract class StepNode : GraphElement
    {
        public const float borderRadius = 6f;
        public const float titleLabelFontSize = 24f;
        public const float subtitleLabelFontSize = 11f;

        internal const float nodeBorderRadius = 8f;

        public const float leftViewAnimationDuration = 0.4f;
        public const float titleLineAnimationDuration = 0.3f;
        public const float titleLabelAnimationDuration = 0.2f;

        /// <summary>
        /// 默认标头颜色
        /// </summary>
        public static readonly Color headColor = new Color32(0, 95, 150, 255);
        public static readonly Color borderNormalColor = new Color32(68, 192, 255, 128);
        public static readonly Color borderHighlightColor = new Color32(68, 192, 255, 255);

        public static readonly float defaultWidth = 200f;

        public bool hasAnyConnection => HasAnyConnection();

        public string title { get => titleLabel.text; set => titleLabel.text = value; }

        public string guid { get => step.guid; set => step.guid = value; }
        public override VisualElement contentContainer => content;
        public override bool muted { get => step.isMute; protected set => step.isMute = value; }

        public virtual float width => defaultWidth;

        public override Vector2 position { get => base.position; set => this.SetPosition(step.drawingData.position = value); }

        public IStep step { get; internal set; }
        /// <summary>
        /// 表示 <see cref="step"/> 所在的流程.
        /// </summary>
        public IProcess process { get; internal set; }

        public GUIFactory guiFactory { get; internal set; }

        protected Label titleLabel;
        protected Label subtitleLabel;

        protected VisualElement head;
        protected VisualElement mask;
        protected VisualElement titleline;

        protected NodeShadow nodeShadow;
        protected NodeBorder nodeBorder;
        protected NodeContent nodeContent;

        private readonly VisualElement content;

        private VisualElement titleView;

        public StepNode()
        {
            style.position = Position.Absolute;
            hierarchy.Add(nodeShadow = new NodeShadow());
            hierarchy.Add(nodeContent = new NodeContent());
            hierarchy.Add(nodeBorder = new NodeBorder());
            InitializeHead();
            InitializeMask();
            nodeContent.Add(content = EditorElementUtility.elementFactory.CreateEditorElementWithName("内容"));

            RegisterCallback<MouseDownEvent>(MouseDownCallback);
            RegisterCallback<MouseEnterEvent>(MouseEnterCallback);
            RegisterCallback<MouseLeaveEvent>(MouseLeaveCallback);
        }

        /// <summary>
        /// 当其它输出端口请求连接到此节点时, 调用该方法.
        /// 总是在该节点被创建后调用该方法.
        /// 覆写该方法以实现自定义的连接方式.
        /// <para>如一个拥有多个输入端口的节点就需要覆写该方法来分配连接请求到各个端口中</para>
        /// </summary>
        /// <returns>如果连接成功, 返回 <see cref="Connectionline"/>; 否则返回 <see cref="null"/></returns>
        public virtual Connectionline RequestConnect(OutputPort outputPort)
        {
            return null;
        }

        /// <summary>
        /// 只供内部使用.
        /// 用于替代构造函数.
        /// 在<see cref="OnCreated"/> 前调用
        /// </summary>
        internal virtual void Initialize()
        {
            position = step.drawingData.position;
            style.SetMinWidth(width);
        }

        /// <summary>
        /// Called when node created.
        /// </summary>
        protected internal virtual void OnCreated()
        {
        }
        /// <summary>
        /// Called when all nodes have been created.
        /// </summary>
        protected internal virtual void OnReady()
        {
        }
        /// <summary>
        /// Called when node Destroyed.
        /// </summary>
        protected internal virtual void OnDestroy()
        {
        }

        protected internal override void OnMute()
        {
            nodeContent.Add(mask);
        }
        protected internal override void OnUnmute()
        {
            nodeContent.Remove(mask);
        }
        protected internal override void OnSelected()
        {
            nodeBorder.style.SetBorderWidth(2f);
            nodeBorder.style.SetBorderColor(borderHighlightColor);
            nodeBorder.PlayAnimation();
            if (this is IInputable inputable)
            {
                foreach (var inputPort in inputable.GetInputPorts())
                {
                    inputPort.connector.EnterHighlightState();
                    foreach (var connectionline in inputPort.connectionlines)
                    {
                        connectionline.EnterHighlightState();
                        connectionline.outputPort.connector.EnterHighlightState();
                    }
                }
            }
            if (this is IOutputable ioutputable)
            {
                foreach (var outputPort in ioutputable.GetOutputPorts())
                {
                    outputPort.connector.EnterHighlightState();
                    foreach (var connectionline in outputPort.connectionlines)
                    {
                        connectionline.EnterHighlightState();
                        connectionline.inputPort.connector.EnterHighlightState();

                    }
                }
            }
        }
        protected internal override void OnUnselected()
        {
            nodeBorder.style.SetBorderColor(Color.clear);
            if (this is IInputable inputable)
            {
                foreach (var inputPort in inputable.GetInputPorts())
                {
                    inputPort.connector.EnterNormaltState();
                    foreach (var connectionline in inputPort.connectionlines)
                    {
                        connectionline.EnterNormaltState();
                        connectionline.outputPort.connector.EnterNormaltState();
                    }
                }
            }
            if (this is IOutputable ioutputable)
            {
                foreach (var outputPort in ioutputable.GetOutputPorts())
                {
                    outputPort.connector.EnterNormaltState();
                    foreach (var connectionline in outputPort.connectionlines)
                    {
                        connectionline.EnterNormaltState();
                        connectionline.inputPort.connector.EnterNormaltState();
                    }
                }
            }
        }

        private bool HasAnyConnection()
        {
            if (this is IInputable inputable && inputable.GetInputPorts().Any(inputPort => inputPort.connectionlines.Any())) return true;
            if (this is IOutputable outputable && outputable.GetOutputPorts().Any(inputPort => inputPort.connectionlines.Any())) return true;
            return false;
        }

        private void InitializeMask()
        {
            mask = EditorElementUtility.elementFactory.CreateEditorElementWithName("静音遮罩");
            mask.StretchToParentSize();
            mask.style.SetBackgroundColor(0, 0, 0, 105);

            Icon muteIcon = EditorElementUtility.elementFactory.CreateIcon(Resources.Load<Texture>("winS.UnityEditor.ProcessEditor/Icon/静音"), 32f);
            muteIcon.style.marginTop = muteIcon.style.marginRight = 8f;
            muteIcon.style.alignSelf = Align.FlexEnd;
            mask.Add(muteIcon);
        }
        private void InitializeHead()
        {
            nodeContent.Add(head = EditorElementUtility.elementFactory.CreateEditorElementWithName("节点头容器"));
            head.pickingMode = PickingMode.Ignore;
            head.style.overflow = Overflow.Hidden;
            head.style.SetBorderTopRadius(borderRadius);
            HeadColorAttribute headColorAttribute = GetType().GetCustomAttribute<HeadColorAttribute>();
            head.style.backgroundColor = headColorAttribute == null ? headColor : headColorAttribute.color;

            //初始化标题视图
            head.Add(titleView = EditorElementUtility.elementFactory.CreateColumn());
            titleView.name = "标题视图";
            titleView.style.top = 0f;
            titleView.pickingMode = PickingMode.Ignore;
            //titleView.style.SetTransition("top", leftViewAnimationDuration, titleLineAnimationDuration);

            //获取标题
            TitleAttribute titleAttribute = GetType().GetCustomAttribute<TitleAttribute>() ?? throw new Exception("无法获取节点标题");
            name = $"{titleAttribute.title} 节点";

            InitializeTitleLabel(titleAttribute.title);
            InitializeTitleline();
            InitializeSubtitleLabel(titleAttribute.subtitle);

            void InitializeTitleLabel(string title)
            {
                titleView.Add(titleLabel = EditorElementUtility.elementFactory.CreateLabelWithName("标题", title));
                titleLabel.pickingMode = PickingMode.Ignore;
                titleLabel.style.alignSelf = Align.FlexStart;

                titleLabel.style.marginTop = 1f;
                titleLabel.style.marginLeft = 7f;
                titleLabel.style.fontSize = titleLabelFontSize;
                titleLabel.style.SetTransformOrigin(0f, 1f);
                //titleLabel.style.SetTransition("scale", titleLabelAnimationDuration, titleLineAnimationDuration);

                TitleColorAttribute titileColorAttribute = GetType().GetCustomAttribute<TitleColorAttribute>();
                if (titileColorAttribute != null) titleLabel.style.SetColor(titileColorAttribute.color);
            }
            void InitializeTitleline()
            {
                titleView.Add(titleline = EditorElementUtility.elementFactory.CreateEditorElementWithName("标题线"));
                titleline.style.width = 0f;
                titleline.style.height = 1f;
                titleline.style.backgroundColor = Color.green;
                //titleline.style.SetTransition("width", titleLineAnimationDuration);
            }
            void InitializeSubtitleLabel(string subtitle)
            {
                titleView.Add(subtitleLabel = EditorElementUtility.elementFactory.CreateLabelWithName("副标题", subtitle));
                subtitleLabel.pickingMode = PickingMode.Ignore;
                subtitleLabel.style.alignSelf = Align.FlexStart;

                subtitleLabel.style.marginLeft = 7f;
                subtitleLabel.style.marginBottom = 2f;
                subtitleLabel.style.fontSize = subtitleLabelFontSize;

                SubtitleColorAttribute subtitleColorAttribute = GetType().GetCustomAttribute<SubtitleColorAttribute>();
                if (subtitleColorAttribute != null) subtitleLabel.style.SetColor(subtitleColorAttribute.color);
            }
        }

        private void MouseDownCallback(MouseDownEvent mouseDownEvent)
        {
            if (mouseDownEvent.button == 2) return;
            if (selected || !selectable) return;
            if (mouseDownEvent.modifiers != EventModifiers.Control) stepGraphView.ClearSelection();
            stepGraphView.AddToSelection(this);
        }
        private void MouseLeaveCallback(MouseLeaveEvent mouseLeaveEvent)
        {
            //titleView.style.top = 0f;

            //titleLabel.style.SetScale(1f);

            nodeBorder.style.SetBorderWidth(1f);
            nodeBorder.style.SetBorderColor(selected ? borderHighlightColor : Color.clear);

            //titleline.style.width = 0f;
        }
        private void MouseEnterCallback(MouseEnterEvent mouseEnterEvent)
        {
            //titleView.style.top = 15f;

            //titleLabel.style.SetScale(1.1f);

            nodeBorder.style.SetBorderWidth(selected ? 2f : 1f);
            nodeBorder.style.SetBorderColor(selected ? borderHighlightColor : borderNormalColor);

            //titleline.style.width = head.layout.width;
        }
    }
}